/*************************************************************************************************
 * 函数功能：
 * 
 * 注意事项：IIC是一种串行同步半双工通信协议
 *          IIC总线的SDA线和SCL线都需要上拉电阻
 * 
 * **********************************************************************************************/
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "my_i2c.h"

i2c_config_t my_i2c_config;

//IIC主机模式初始化函数，返回值：0，成功
esp_err_t MY_I2C_Master_Init(void)
{
    my_i2c_config.mode = I2C_MODE_MASTER;  //选择主机模式
    my_i2c_config.sda_io_num = Master_SDA_NUM;  //设置SDA管脚
    my_i2c_config.scl_io_num = Master_SCL_NUM;  //设置SCL管脚
    my_i2c_config.sda_pullup_en = GPIO_PULLUP_ENABLE;  //SDA管脚上拉
    my_i2c_config.scl_pullup_en = GPIO_PULLUP_ENABLE;  //SCL管脚上拉
    my_i2c_config.master.clk_speed = Master_SPEED;  //设置时钟频率
    i2c_param_config(Master_PORT, &my_i2c_config);  //选择I2C端口0

    i2c_driver_install(Master_PORT, I2C_MODE_MASTER, 0, 0, 0);  //安装驱动程序

    return 0;
}

esp_err_t MY_I2C_Write_Byte(uint8_t addr, uint8_t reg, uint8_t data)
{
    esp_err_t error;

    //创建一个命令链接
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();

    //启动位
    i2c_master_start(cmd);

    //发送从机地址，提供单字节地址作为调用此函数的实参
    error = i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, 1);
    if(error != ESP_OK)
    {
        return -1;
    }

    error = i2c_master_write_byte(cmd, reg, 1);
    if(error != ESP_OK)
    {
        return -1;
    }

    error = i2c_master_write_byte(cmd, data, 1);
    if(error != ESP_OK)
    {
        return -1;
    }

    //停止位
    i2c_master_stop(cmd);

    //触发I2C控制器执行命令链接，一旦开始执行，就不能再修改命令链接
    i2c_master_cmd_begin(Master_PORT, cmd, 10 / portTICK_PERIOD_MS);

    //释放命令链接使用的资源
    i2c_cmd_link_delete(cmd);
    return 0;
}


esp_err_t MY_I2C_Write_Len(uint8_t addr, uint8_t reg, uint8_t len, uint8_t *data)
{
    esp_err_t error;

    //创建一个命令链接
    i2c_cmd_handle_t cmd = i2c_cmd_link_create(); 

    //启动位
    i2c_master_start(cmd); 

    error = i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, 1);
    if(error != ESP_OK)
    {
        return -1;
    }    

    error = i2c_master_write_byte(cmd, reg, 1);
    if(error != ESP_OK)
    {
        return -1;
    }

    error = i2c_master_write(cmd, data, len, 1);
    if(error != ESP_OK)
    {
        return -1;
    }
    //停止位
    i2c_master_stop(cmd);  

    //触发I2C控制器执行命令链接，一旦开始执行，就不能再修改命令链接
    i2c_master_cmd_begin(Master_PORT, cmd, 10 / portTICK_RATE_MS); 

    //释放命令链接使用的资源
    i2c_cmd_link_delete(cmd);
    return 0;
}

esp_err_t MY_I2C_Read_Byte(uint8_t addr, uint8_t reg, uint8_t *res)
{
    esp_err_t error;

    //创建一个命令链接
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();  

    //启动位
    i2c_master_start(cmd); 

    //发送从机地址，提供单字节地址作为调用此函数的实参
    error = i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, 1);
    if(error != ESP_OK)
    {
        return -1;
    }

    error = i2c_master_write_byte(cmd, reg, 1);
    if(error != ESP_OK)
    {
        return -1;
    }
    
    i2c_master_start(cmd);
    error = i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_READ, 1);
     if(error != ESP_OK)
    {
        return -1;
    }

    error = i2c_master_read_byte(cmd, res, I2C_MASTER_LAST_NACK);
     if(error != ESP_OK)
    {
        return -1;
    }

    //停止位
    i2c_master_stop(cmd);  

    //触发I2C控制器执行命令链接，一旦开始执行，就不能再修改命令链接
    i2c_master_cmd_begin(Master_PORT, cmd, 10 / portTICK_RATE_MS); 

    //释放命令链接使用的资源
    i2c_cmd_link_delete(cmd);
    return 0;
}

esp_err_t MY_I2C_Read_Len(uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf)
{
    esp_err_t error;
    //创建一个命令链接
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    
    //启动位
    i2c_master_start(cmd);

    //发送器件地址+写命令
    error = i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, 1);
    if(error != ESP_OK)
    {
        return -1;
    }

    error = i2c_master_write_byte(cmd, reg, 1);
    if(error != ESP_OK)
    {
        return -1;
    }

    i2c_master_start(cmd);
    error = i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_READ, 1);
    if(error != ESP_OK)
    {
        return -1;
    }

    error = i2c_master_read(cmd, buf, len, I2C_MASTER_LAST_NACK);
    if(error != ESP_OK)
    {
        return -1;
    }

    //停止位
    i2c_master_stop(cmd);

    //触发I2C控制器执行命令链接，一旦开始执行，就不能再修改命令链接
    i2c_master_cmd_begin(Master_PORT, cmd, 100 / portTICK_RATE_MS); 

    //释放命令链接使用的资源
    i2c_cmd_link_delete(cmd);
    return 0;
}


